<?php
/**
 * @class		EditablePage
 * @ingroup		editable_pages_models
 * @brief		Model của đối tượng EditablePage, bao gồm các phương thức phục vụ cho việc giao tiếp với bảng dữ liệu editable_pages
 * @author		BinhQD
 * @version		1.1
 * @date		2010-04-22
 */
class EditablePage extends AppModel {
	/**
	 @var $name
	 @brief Tên của model
	 */
	var $name = 'EditablePage';
	/**
	 * @var $actsAs
	 * @brief Biến dùng để cấu hình
	 */
	var $actsAs = array(
		'Sluggable'	=>	array(
			'label'	=>	'title',
			'alias'	=>	'alias'
		),
		'HasSingleImage'	=>	array(
			'image_field'	=>	'image'
		),
		'ExtendedValidation',
		'ExtendedConfiguration'	=> array(
			'configFolder'		=>	'editable_pages',
			'cacheName'		=> 'editable_page_config',
			'names'		=> array('EditablePage', 'Themes', 'View', 'Appearence')
		),
		'HasRelatedImages',
		'Containable',
		'Translate'	=>	array('title','description','content'),
		'ExtendedTranslate'
//		'MultiLocale'	=>	array(
//			'fields'	=>	array('title','description','content')
//		)
	);
	
	/**
	 * @var $hasAndBelongsToMany
	 * @brief Biến dùng để ràng buộc dữ liệu đầu vào
	 */
	var $hasAndBelongsToMany = array(
		'Category' => array(
			'className' => 'Category',
			'joinTable' => 'editable_pages_categories',
			'foreignKey' => 'page_id',
			'associationForeignKey' => 'category_id',
			'unique' => true,
			'conditions' => '',
			'fields' => '',
			'order' => '',
			'limit' => '',
			'offset' => '',
			'finderQuery' => '',
			'deleteQuery' => '',
			'insertQuery' => ''
		)
	);
	
	/**
	 * @var $validate
	 * @brief Biến dùng để ràng buộc dữ liệu đầu vào
	 */
	var $validate = array(
		'title'	=>	array(
			'rule-title-1'	=>	array(
				'rule'	=>	'notempty',
				'message'	=>	"Page title can't be left blank",
			)
		),
		'content'	=>	array(
			'rule-content-1'	=>	array(
				'rule'	=>	'notempty',
				'message'	=>	"Page content can't be left blank",
			)
		)
	);
	
	var $dataCloner = array();
	var $overrideTranslation = array();
	/**
	 * Phương thức được sử dụng để xóa hình ảnh khỏi ổ cứng, bao gồm hình chính và thumbnail nếu có
	 * @param $image_name Tên của file hình cần xóa
	 * @param $config Thông tin cấu hình nếu có (Không bắt buộc)
	 * @return Không trả về dữ liệu
	 */
	function __delete_image($image_name, $config = array()) {
		if (!count($config)) {
			$config = $this->loadConfig();
		}
		// Xử lý để lấy tên thumbnail
		$ext = strrchr($image_name, ".");
		$pos = strrpos($image_name, ".");
		$filename = substr($image_name,0,$pos);
		$thumbnail_name = $filename."_thumbnail".$ext;
		if (is_file($config['image']['path'].$image_name)) {
			@unlink($config['image']['path'].$image_name);
			@unlink($config['thumbnail']['path'].$thumbnail_name);
		}
	}
	
	/**
	 * Phương thức dùng để trả về dữ liệu danh sách của các trang thuộc danh mục root và cấp con
	 * @param $controller Biến tham chiếu $controller được truyền vào để sử dụng cho mục đích phân trang
	 * @param $configs Thông tin cấu hình nếu có (Không bắt buộc)
	 * @return $pages Mảng các thông tin cần lấy theo tiêu chí phân trang, đồng thời cập nhật trạng thái phân trang vào $controller
	 */
	function getList(&$controller, $configs = array()) {
		if (!count($configs)) {
			$configs = $this->loadConfig();
		}
		
		$conditions = array();
		if ($controller->category_root_id != null) {
			$category_ids = $this->getChildCatIds(array('root_id' => $controller->category_root_id));
			// Load Child Category Id
			if (count($category_ids)) {
				$conditions = array(
					'ReferenceCategory.category_id'	=>	$category_ids
				);
			}
		}

		$extraFields = array();
		if (isset($configs[$this->name]['order']) && $configs[$this->name]['order']['orderable']) {
			$extraFields = array("{$this->name}.priority");
		}
		
		$limit = 20;
		if (isset($configs['View']) && isset($configs['View']['limit'])) {
			$limit = $configs['View']['limit'];
		}
		
		$order = array("{$this->name}.priority desc");
		$contains = array();
		if (isset($configs[$this->name]['order']) && isset($configs[$this->name]['order']['defaultSortField'])) {
			$order = array_merge(array($configs[$this->name]['order']['defaultSortField']), $order);
			
			$pos = strrpos($configs[$this->name]['order']['defaultSortField'], ".");
			if ($pos > 0) {
				$modelName = substr($configs[$this->name]['order']['defaultSortField'], 0, $pos);
				if ($modelName != $this->name && !isset($this->{$modelName})) {
					$this->bindModel(
						array('hasOne' => array(
							"{$modelName}" => array(
								"className" 	=> "{$modelName}",
								"foreignKey"	=> "foreign_id"
							)
						)
					), false);
					$contains = array($modelName);
				}
			}
		}

		$controller->paginate[$this->name] = array(
			'conditions'	=>	$conditions,
			'contain'		=>	$contains,
			'fields'		=>	array_merge(array("{$this->name}.id","{$this->name}.alias","{$this->name}.title","Category.name", "{$this->name}.image"),$extraFields),
			'order'			=>	$order,
			'joins' => array(
				array(
					'table' => $this->hasAndBelongsToMany['Category']['joinTable'],
					'type' => 'INNER',
					'alias' => 'ReferenceCategory',
					'conditions' => array(
						"{$this->name}.id = ReferenceCategory.page_id"
					)
				),
				array(
					'table' => $this->Category->table,
					'type' => 'INNER',
					'alias' => 'Category',
					'conditions' => array(
						"Category.id = ReferenceCategory.category_id"
					)
				)
			),
			'limit'	=>	$limit
		);
		
		$pages = $controller->paginate($this->name);

		return $pages;
	}
	
	/**
	 * Phương thức được sử dụng để lấy ra danh sách các danh mục con của một danh mục nào đó, được sử dụng cho việc lấy ra tất cả các trang (con và cháu) trong một danh mục
	 * @param $options Thông tin cần sử dụng để lọc dữ liệu, bao gồm root_id của danh mục cần lấy con và cháu
	 * @return $category_ids Danh sách các danh mục con của danh mục truyền vào
	 */
	function getChildCatIds($options = array()) {

		$conditions = array();
		$category_ids = $this->Category->find('list', array(
			'conditions'	=>	array(
				'Parent.id'	=> $options['root_id']
			),
			'fields'	=>	array('id','id'),
			'joins' => array(
				array(
					'table' => $this->Category->table,
					'type' => 'INNER',
					'alias' => 'Parent',
					'conditions' => array(
						"Category.lft >= Parent.lft",
						"Category.rght <= Parent.rght",
					)
				)
			)
		));

		return $category_ids;
	}
	
	/**
	 * Tương tự như phương thức getList(), phương thức getPagesInCategory() được sử dụng để trả về dữ liệu danh sách của các trang thuộc danh mục có alias là $alias (Chỉ lấy các trang trực tiếp thuộc về danh mục này)
	 * @param $controller Biến tham chiếu $controller được truyền vào để sử dụng cho mục đích phân trang
	 * @param $alias Alias của danh mục cần lấy thông tin phân trang
	 * @param $fields Các trường dữ liệu cần lấy ra
	 * @param $options Các tùy chọn phụ trợ cho việc truy vấn dữ liệu, ví dụ contain, limit, order, ...
	 * @return $pages Mảng các thông tin cần lấy theo tiêu chí phân trang, đồng thời cập nhật trạng thái phân trang vào $controller
	 */
	function getPagesInCategory(&$controller, $alias, $fields, $options = array()) {
		if (isset($options['contain'])) {
			foreach ($options['contain'] as $item) {
				if ($item != $this->name) {
					$this->bindModel(
						array('hasOne' => array(
							"{$item}" => array(
								"className" 	=> "{$item}",
								"foreignKey"	=> "foreign_id"
							)
						)
					), false);
				}
			}
		}

		$pag_options = array_merge(array(
				'conditions'	=>	array("Category.alias" => $alias),
				'fields'		=>	$fields,
				'joins' => array(
					array(
						'table' => $this->hasAndBelongsToMany['Category']['joinTable'],
						'type' => 'INNER',
						'alias' => 'ReferenceCategory',
						'conditions' => array(
							"{$this->name}.id = ReferenceCategory.page_id"
						)
					),
					array(
						'table' => $this->Category->table,
						'type' => 'INNER',
						'alias' => 'Category',
						'conditions' => array(
							"Category.id = ReferenceCategory.category_id"
						)
					)
				)
			), $options);
			
		$controller->paginate[$this->name] = $pag_options;
		$pages = $controller->paginate($this->name);
		return $pages;
		//$pages = $controller->paginate($this->name);
	}
	
	/**
	 * Tương tự như phương thức getPagesInCategory(), phương thức getAllPagesInCategory() lấy tất cả các trang của danh mục, không phân trang
	 * @param $alias Alias của danh mục cần lấy thông tin
	 * @param $fields Các trường dữ liệu cần lấy ra
	 * @param $options Các tùy chọn phụ trợ cho việc truy vấn dữ liệu, ví dụ contain, limit, order, ...
	 * @return $pages Mảng tất cả các trang cần lấy
	 */
	function getAllPagesInCategory($alias, $fields, $options = array()) {
		if (isset($options['contain'])) {
			if (!is_array($options['contain'])) {
				$options['contain'] = array($options['contain']);
			}
			foreach ($options['contain'] as $item) {
				if ($item != $this->name) {
					$this->bindModel(
						array('hasOne' => array(
							"{$item}" => array(
								"className" 	=> "{$item}",
								"foreignKey"	=> "foreign_id"
							)
						)
					), false);
				}
			}
		}
		
		$this->Category = new $this->hasAndBelongsToMany['Category']['className'];
		$pag_options = array_merge(array(
				'conditions'	=>	array("Category.alias" => $alias),
				'fields'		=>	$fields,
				'joins' => array(
					array(
						'table' => $this->hasAndBelongsToMany['Category']['joinTable'],
						'type' => 'INNER',
						'alias' => 'ReferenceCategory',
						'conditions' => array(
							"{$this->name}.id = ReferenceCategory.page_id"
						)
					),
					array(
						'table' => $this->Category->table,
						'type' => 'INNER',
						'alias' => 'Category',
						'conditions' => array(
							"Category.id = ReferenceCategory.category_id"
						)
					)
				),
				"limit"	=>	null
			), $options);
			
		$pages = $this->find('all', $pag_options);
		
		return $pages;
	}
	
	/**
	 * Phương thức deletePage() được sử dụng để xóa 1 trang thông tin, bao gồm cả việc xóa hình ảnh của trang ra khỏi ổ cứng
	 * @param $id ID của trang cần xóa
	 * @return Không trả về dữ liệu
	 */
	function deletePage($id) {
		$this->deleteImage($id);
		$this->delete($id);
	}
	
	function getRelatedInfo(&$controller, $id, $fields = array(), $options = array()) {
		// Load Related Pages if exists
		$related_pages = array();
		$relatedInfo = array();
		if (isset($this->relatedInfo)) {
			$relatedInfo = $this->relatedInfo;
		}
		
		if (isset($relatedInfo) && isset($relatedInfo['hasMany']) && !empty($relatedInfo['hasMany'])) {
			foreach ($relatedInfo['hasMany'] as $name => $item) {
				// Load model
				$controller->loadModel($item['model']);
				
				// Trích chính xác tên plugin & model
				if (strpos($item['model'], '.') !== false) {
					list($plugin, $modelClass) = explode('.', $item['model']);
				} else {
					$plugin = null;
					$modelClass = $item['model'];
				}
				
				$config = $this->loadConfig(array(
					'config_folder'		=>	$item['config'],
					'names'				=> array($modelClass, 'Category', 'RelatedPages')
				));

				
				
				if (empty($fields)) {
					$extraFields = array("{$modelClass}.priority");
					$fields = array_merge(array("{$modelClass}.id","{$modelClass}.alias","{$modelClass}.title","Category.name"),$extraFields);
				}
				
				$options = array(
					'conditions'	=>	array(
						'RelatedReference.foreign_key'	=>	$id,
						'RelatedReference.model'		=>	$this->name,
						'RelatedReference.group'		=>	$name
					),
					'fields'		=>	$fields,
					'joins' => array(
						array(
							'table' => $controller->{$modelClass}->hasAndBelongsToMany['Category']['joinTable'],
							'type' => 'INNER',
							'alias' => 'ReferenceCategory',
							'conditions' => array(
								"{$modelClass}.id = ReferenceCategory.page_id"
							)
						),
						array(
							'table' => $controller->{$modelClass}->Category->table,
							'type' => 'INNER',
							'alias' => 'Category',
							'conditions' => array(
								"Category.id = ReferenceCategory.category_id"
							)
						),
						array(
							'table' => 'related_pages',
							'type' => 'INNER',
							'alias' => 'RelatedReference',
							'conditions' => array(
								$modelClass . ".id = RelatedReference.related_page_foreign_key",
								"RelatedReference.related_page_model"	=>	$modelClass
							)
						)
					),
				) + $options;
				
				$controller->paginate[$modelClass] = $options;
				$records = $controller->paginate($modelClass);
				if (!empty($records)) {
					$related_pages[ $name] = array(
						'data'		=> $records,
						'configs'	=> $config,
						'relatedInfo'	=>	$item
					);
				}
			}
		}
		return $related_pages;
	}
}
?>